local snow    = require("meet_your_mods.mhr").snow
local via     = require("meet_your_mods.mhr").via
local status  = require("meet_your_mods.status")
local setting = require("meet_your_mods.setting")
local ui      = require("meet_your_mods.ui")

via.Prefab:fetch_method("create_on_vector3f", "instantiate(via.vec3)")

local berserker = {
    setting = {
        no_zako       = true, --无野生小怪
        spiribird     = false, --生成彩虹鬼火鸟
        no_pacify     = true, --移除怪异钝化
        no_calm       = false, --怪异凶化无法镇压
        no_marionette = true, --移除玩家/随从/盟友攻击的御龙值
        no_wire_bind  = true, --移除铁虫猎犬具特效
        ignore_damage = true, --攻击不会减少待操计时
    },

    bird = nil,
    blank_bird = {},
}

function berserker:pre_setupEnemyZakoSetData(_)
    if self.setting.no_zako and not status:is_online() then
        return sdk.PreHookResult.SKIP_ORIGINAL
    end
    return sdk.PreHookResult.CALL_ORIGINAL
end

function berserker:pre_endMysteryMaximumActivity(parameters)
    if self.setting.no_pacify
        and not status:is_online()
        and 1 == sdk.to_int64(parameters[3])
        and 1 == sdk.to_int64(parameters[4])
    then
        parameters[4] = sdk.to_ptr(0)
    end
    return sdk.PreHookResult.CALL_ORIGINAL
end

function berserker:pre_updateMystery(parameters)
    if not self.setting.no_calm or status:is_online() then
        return sdk.PreHookResult.CALL_ORIGINAL
    end

    local monster = sdk.to_managed_object(parameters[2])
    if snow.enemy.EnemyCharacterBase.isEnableMystery(monster) then
        snow.enemy.EnemyMysteryParam.set_MaximumActivityReleaseDamageStock(
            snow.enemy.EnemyCharacterBase.get_MysteryParam(monster), 0)
    end

    return sdk.PreHookResult.CALL_ORIGINAL
end

function berserker:pre_afterCalcDamage_DamageSide(parameters)
    if not self.setting.no_marionette
        and not self.setting.no_wire_bind
        and not self.setting.ignore_damage
        or status:is_online()
    then
        return sdk.PreHookResult.CALL_ORIGINAL
    end

    local damage    = snow.hit.EnemyCalcDamageInfo.AfterCalcInfo_DamageSide(sdk.to_managed_object(parameters[3]))
    local parameter = damage._CalcParam
    local owner     = parameter:get_OwnerType()

    if self.setting.no_marionette and damage:get_IsMarionetteStartDamageStock()
        and (snow.hit.DamageFlowOwnerType.Player == owner
            or snow.hit.DamageFlowOwnerType.PlayerShell == owner
            and (parameter:get_CalcType() ~= snow.enemy.EnemyDef.DamageCalcType.Shell
                or damage:get_DamageAttackerType() ~= snow.enemy.EnemyDef.DamageAttackerType.Invalid)
            or snow.hit.DamageFlowOwnerType.Otomo == owner
            or snow.hit.DamageFlowOwnerType.OtomoShell == owner)
    then
        damage:set_IsMarionetteStartDamageStock(false)
    end

    if self.setting.no_wire_bind
        and (snow.hit.DamageFlowOwnerType.Otomo == owner
            or snow.hit.DamageFlowOwnerType.OtomoShell == owner)
        and damage:get_IsBindWire()
    then
        damage:set_IsBindWire(false)
        damage:set_BindWireConnectTargetId(0)
    end

    if self.setting.ignore_damage and damage:get_IsSubMarionetteStartWaitTimer()
    then
        damage:set_IsSubMarionetteStartWaitTimer(false)
    end

    return sdk.PreHookResult.CALL_ORIGINAL
end

function berserker:initialize()
    snow.enemy.EnemyManager.setupEnemyZakoSetData:sdk_auto_hook(self)
    snow.enemy.EnemyCharacterBase.endMysteryMaximumActivity:sdk_auto_hook(self)
    snow.enemy.EnemyCharacterBase.updateMystery:sdk_auto_hook(self)
    snow.enemy.EnemyCharacterBase.afterCalcDamage_DamageSide:sdk_auto_hook(self)

    snow.QuestManager.updateQuestTime:sdk_hook(nil, function(_) self:on_quest_timer() end)
    snow.QuestManager.updateQuestEndFlow:sdk_hook(nil, function(_) self:on_quest_ending() end)
    re.on_script_reset(function()
        if self.bird then self:release_bird() end
    end)

    setting:bind_setting("berserker", self.setting)

    ui:cluster("fatal_quest", "任务关键功能")
    ui:checkbox("fatal_quest", "berserker", "no_zako", "无野生小怪")
    ui:checkbox("fatal_quest", "berserker", "spiribird", "生成彩虹鬼火鸟")
    ui:checkbox("fatal_quest", "berserker", "no_pacify", "移除怪异钝化")
    ui:checkbox("fatal_quest", "berserker", "no_calm", "强力怪异凶化")
    ui:checkbox("fatal_quest", "berserker", "no_marionette", "关闭非斗兽御龙")
    ui:checkbox("fatal_quest", "berserker", "no_wire_bind", "移除速射炮特效")
    ui:checkbox("fatal_quest", "berserker", "ignore_damage", "待操沙包")
end

function berserker:normalize()
end

--召唤鬼火鸟
function berserker:spawn_bird()
    --在自带彩虹鬼火鸟的地图不召唤鬼火鸟
    local map = status:current_map()
    if snow.QuestMapManager.MapNoType.infernal_springs == map
        or snow.QuestMapManager.MapNoType.arena == map
        or snow.QuestMapManager.MapNoType.forlorn_arena == map
        or snow.QuestMapManager.MapNoType.coral_palace == map
        or snow.QuestMapManager.MapNoType.yawning_abyss == map
    then
        self.bird = self.blank_bird
        return
    end

    local position = status:current_position()
    if not position then
        log.info("position")
        return
    end

    --EnvironmentCreatureManager会在任务结束时销毁，进入任务时重建
    local bird_manager = snow.envCreature.EnvironmentCreatureManager:get_singleton(true)
    if not bird_manager then
        return
    end

    local prefab = bird_manager._EcPrefabList[15]
    while not prefab:get_Standby() do
        prefab:set_Standby(true)
    end

    local bird = prefab:create_on_vector3f(position)
    while not bird or not sdk.is_managed_object(bird:get_instance()) do
        bird = prefab:create_on_vector3f(position)
    end
    self.bird = bird
end

function berserker:release_bird()
    if self.bird ~= self.blank_bird then
        via.GameObject:destroy(self.bird:get_instance())
    end
    self.bird = nil
end

function berserker:on_quest_timer()
    if not self.setting.spiribird or self.bird or status:is_online() then
        return
    end
    self:spawn_bird()
end

function berserker:on_quest_ending()
    if not self.setting.spiribird or not self.bird then
        return
    end
    self:release_bird()
end

return berserker
